package com.isyscore.os.metadata.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.isyscore.device.common.util.BeanMapper;
import com.isyscore.os.core.entity.SqlQuery;
import com.isyscore.os.core.entity.SqlQueryGroup;
import com.isyscore.os.core.exception.DataFactoryException;
import com.isyscore.os.core.exception.ErrorCode;
import com.isyscore.os.core.mapper.SqlQueryGroupMapper;
import com.isyscore.os.core.util.InitiallyUtils;
import com.isyscore.os.metadata.model.dto.SqlTreeItemDTO;
import com.isyscore.os.metadata.model.entity.DataSource;
import com.isyscore.os.metadata.model.vo.SqlQueryVO;
import com.isyscore.os.metadata.service.DataSourceService;
import com.isyscore.os.metadata.service.SqlQueryGroupService;
import com.isyscore.os.metadata.service.SqlQueryService;
import com.isyscore.os.permission.common.constants.PermissionConstants;
import lombok.RequiredArgsConstructor;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 服务实现类
 *
 * @author starzyn
 * @since 2022-03-16
 */
@Service
@RequiredArgsConstructor
public class SqlQueryGroupServiceImpl extends ServiceImpl<SqlQueryGroupMapper, SqlQueryGroup> implements SqlQueryGroupService {
    private final SqlQueryService sqlQueryService;
    private final DataSourceService dataSourceService;

    @Override
    public List<SqlQueryGroup> listWithInitially() {
        List<SqlQueryGroup> sqlQueryGroup = list();
        SqlQueryGroup sqlQueryGroupInitially = InitiallyUtils.markInitially(() -> getOne(Wrappers.lambdaQuery(SqlQueryGroup.class).eq(SqlQueryGroup::getTenantId, PermissionConstants.GLOBAL_BUSINESS_DATA_TENANT_ID_KEY)));
        sqlQueryGroup.add(sqlQueryGroupInitially);
        return sqlQueryGroup;
    }

    @Override
    public List<SqlTreeItemDTO> getSqlQueryTree(String sqlName) {
        List<SqlQuery> sqls = null;
        LambdaQueryWrapper<SqlQuery> qw = new LambdaQueryWrapper<>();
        if (!Strings.isNullOrEmpty(sqlName)) {
            qw.like(SqlQuery::getName, sqlName);
        }
        qw.orderByDesc(SqlQuery::getCreateTime);
        sqls = sqlQueryService.list(qw);
        LambdaQueryWrapper<SqlQueryGroup> groupQw = new LambdaQueryWrapper<>();
        groupQw.orderByDesc(SqlQueryGroup::getCreateTime);
        List<SqlQueryGroup> groups = this.list(groupQw);
        SqlQueryGroup sqlQueryGroupInitially = InitiallyUtils.markInitially(() -> getOne(Wrappers.lambdaQuery(SqlQueryGroup.class).eq(SqlQueryGroup::getTenantId, PermissionConstants.GLOBAL_BUSINESS_DATA_TENANT_ID_KEY)));
        groups.add(sqlQueryGroupInitially);
        List<SqlTreeItemDTO> treeItems = Lists.newArrayList();
        Map<Long, SqlTreeItemDTO> groupMap = Maps.newLinkedHashMap();
        for (SqlQueryGroup group : groups) {
            SqlTreeItemDTO groupItem = new SqlTreeItemDTO();
            groupItem.setId(group.getId());
            groupItem.setType(1);
            groupItem.setLabel(group.getName());
            groupMap.put(groupItem.getId(), groupItem);
        }
        for (SqlQuery sqlQuery : sqls) {
            SqlTreeItemDTO metricItem = new SqlTreeItemDTO();
            metricItem.setId(sqlQuery.getId());
            metricItem.setType(2);
            metricItem.setLabel(sqlQuery.getName());
            SqlTreeItemDTO group = groupMap.get(sqlQuery.getGroupId());
            if (group != null) {
                if (group.getChildren() == null) {
                    group.setChildren(Lists.newArrayList());
                }
                group.getChildren().add(metricItem);
            } else {
                treeItems.add(metricItem);
            }
        }
        Collection<SqlTreeItemDTO> groupItems = groupMap.values();
        //仅将存在子节点的分组（如果查询条件为空则全部加入）加入到树形结构中
        for (SqlTreeItemDTO groupItem : groupItems) {
            if (groupItem.getChildren() != null || Strings.isNullOrEmpty(sqlName)) {
                treeItems.add(groupItem);
            }
        }
        return treeItems;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void removeGroup(String id) {
        SqlQueryGroup sqlQueryGroup = getById(id);
        if (ObjectUtil.isNull(sqlQueryGroup)) {
            throw new DataFactoryException(ErrorCode.DATA_NOT_FOUND,id);
        }
        //默认分组校验，不允许删除
        if (Objects.equals(sqlQueryGroup.getTenantId(), PermissionConstants.GLOBAL_BUSINESS_DATA_TENANT_ID_KEY)) {
            throw new DataFactoryException(ErrorCode.INITIALLY_DATA_NOT_ALLOWED_DELETE);
        }
        //非空分组校验，不允许删除
        List<SqlQuery> sqlQueries = sqlQueryService.list(Wrappers.<SqlQuery>lambdaQuery().eq(SqlQuery::getGroupId, sqlQueryGroup.getId()));
        if (CollUtil.isNotEmpty(sqlQueries)) {
            throw new DataFactoryException(ErrorCode.DATA_NOT_ALLOWED_DELETE,"分组下存在SQL查询数据");
        }
        this.removeById(sqlQueryGroup.getId());
    }

    @Override
    public SqlQueryVO getSqlQueryVO(String id) {
        SqlQuery sqlQuery=sqlQueryService.getById(id);
        DataSource dataSource= InitiallyUtils.markInitially(() ->dataSourceService.getById(sqlQuery.getDataSourceId()));
        SqlQueryGroup sqlQueryGroup=InitiallyUtils.markInitially(() ->getById(sqlQuery.getGroupId()));
        SqlQueryVO sqlQueryVO=SqlQueryVO.builder()
                .groupName(ObjectUtil.isNotNull(sqlQueryGroup)?sqlQueryGroup.getName():"")
                .dataSourceName(dataSource.getName())
                .dataSourceType(dataSource.getType())
                .build();
        BeanMapper.copy(sqlQuery,sqlQueryVO);
        return sqlQueryVO;
    }
    @Override
    public void importData(List<SqlQueryGroup> sqlQueryGroups){
        if (sqlQueryGroups.isEmpty()) {
            return;
        }
        Set<Long> sqlQueryGroupSets = Sets.newConcurrentHashSet();
        for (SqlQueryGroup sqlQueryGroup : sqlQueryGroups) {
            sqlQueryGroupSets.add(sqlQueryGroup.getId());
        }
        //删除模型
        LambdaQueryWrapper<SqlQueryGroup> sqlQueryLambdaQueryWrapper = new LambdaQueryWrapper<>();
        sqlQueryLambdaQueryWrapper.in(SqlQueryGroup::getId, sqlQueryGroupSets);
        this.remove(sqlQueryLambdaQueryWrapper);
        this.saveBatch(sqlQueryGroups);
    }
}
